using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace RapidHDL
{
    public partial class ChipClock : UserControl
    {
        RapidHardware oRapidHardware;
        public delegate void UpdateHandler();
        public event UpdateHandler Updated;

        DateTime dStartTime;

        MicroTrace oMicroTrace = null;
        string sCodeLine = "";

        SignalView oPC;
        SignalView oOp;

        public void AttachMicroTrace(MicroTrace poMicroTrace)
        {
            oMicroTrace = poMicroTrace;
        }

        public ChipClock()
        {
            InitializeComponent();
        }
    
        public RapidHardware RapidHardware
        {
            get
            {
                return oRapidHardware;
            }
            set
            {
                oRapidHardware = value;
                if (oRapidHardware == null)
                    return;
                DoIOTest();
                if (oRapidHardware.Settings.RunFromXilinx)
                {
                    if (!oRapidHardware.Structure.FileChanged)
                    {
                        cmdBuildHardware.Text = "Build Hardware";
                    }
                    else
                    {
                        cmdBuildHardware.Text = "Build Hardware (Required!)";
                    }
                }
                else
                {
                    cmdBuildHardware.Visible = false;
                }
                cmdReset_Click(this, null);
            }
        }

        string sNextOpSignal = "";
        string sPCSignal = "";

        public void AttachMicro(string psNextOpSignal, string psPCSignal)
        {
            cmdMicroStep.Visible = true;
            cmdMicroDBG.Visible = true;
            lblMicroAddress.Visible = true;
            sNextOpSignal = psNextOpSignal;
            sPCSignal = psPCSignal;
            oPC = RapidHardware.SystemInterface.GetSignalView(sPCSignal);
            oOp = RapidHardware.SystemInterface.GetSignalView(sNextOpSignal);
        }

        private void UpdateEvent()
        {
            bool bClockRunning = oRapidHardware.SystemInterface.SystemControl.IsClockRunning();
            if (bClockRunning)
                oRapidHardware.SystemInterface.SystemControl.StopClock();
            
            oRapidHardware.DisplayManager.Refresh();
            if (Updated != null)
                Updated();

            if (bClockRunning)
                oRapidHardware.SystemInterface.SystemControl.StartClock();

            if (oRapidHardware.SystemInterface.SystemControl.IsClockRunning())
            {
                cmdClock.Text = "Clock - On";
            }
            else
            {
                cmdClock.Text = "Clock - Off";
            }
        }

        private void cmdReset_Click(object sender, EventArgs e)
        {
            oRapidHardware.SystemInterface.SystemControl.Reset();
            oRapidHardware.SystemInterface.ApplySignalSourceDefaults();
            lblClock.Text = "0";
            UpdateEvent();
        }

        private void cmdStep_Click(object sender, EventArgs e)
        {
            oRapidHardware.SystemInterface.SystemControl.Go((int)txtCycles.Value);
            long lCycles = oRapidHardware.SystemInterface.SystemControl.ClockCycles();
            lblClock.Text = lCycles.ToString();
            UpdateEvent();
        }

        private bool IOTest()
        {
            const string IO_TEST_SOURCE = "io_test_source";
            const string IO_TEST_VIEW = ".io_test";

            SignalSource oSource = RapidHardware.SystemInterface.GetSignalSource(IO_TEST_SOURCE);
            SignalView oView = RapidHardware.SystemInterface.GetSignalView(IO_TEST_VIEW);
            oSource.ValueAsInt = 55;
            if (oView.ValueAsInt != 55)
            {
                RapidHardware.Transcript.AddTranscript("IO Test Failed");
                return false;
            }
            oSource.ValueAsInt = 0;
            if (oView.ValueAsInt != 0)
            {
                RapidHardware.Transcript.AddTranscript("IO Test Failed - Test B");
                return false;
            }
            oSource.ValueAsInt = 10;
            if (oView.ValueAsInt != 10)
            {
                RapidHardware.Transcript.AddTranscript("IO Test Failed - 10");
                return false;
            }
            RapidHardware.Transcript.AddTranscript("STARTUP IO Test Complete");
            return true;
        }

        private void DoIOTest()
        {
            if (IOTest())
            {
                cmdStatus.Text = "Status - OK";
            }
            else
            {
                cmdStatus.Text = "IO Error";
            }
        }

        private void cmdStatus_Click(object sender, EventArgs e)
        {
            DoIOTest();
            System.Windows.Forms.MessageBox.Show(RapidHardware.Transcript.GetTranscript());
        }

        private void lblClock_Click(object sender, EventArgs e)
        {

        }

        private void cmdBuildHardware_Click(object sender, EventArgs e)
        {
            dStartTime = DateTime.Now;
            tmrBuild.Enabled = true;

            bool bResult = oRapidHardware.Structure.BuildHardware(false);
            tmrBuild.Enabled = false;

            if (bResult)
            {
                cmdBuildHardware.Text = "Hardware Build Complete";
                IOTest();
            }
            else
            {
                cmdStatus.Text = "Hardware Error";
                cmdBuildHardware.Text = "Hardware Build Not Ready";
            }
        }

        private void tmrBuild_Tick(object sender, EventArgs e)
        {
            TimeSpan tsDiff = DateTime.Now - dStartTime;
            cmdBuildHardware.Text = "Building Hardware {" + tsDiff.Minutes.ToString() + ":" + tsDiff.Seconds.ToString() + "}";
        }

        private void cmdScript_Click(object sender, EventArgs e)
        {
            oRapidHardware.HardwareScripts.DoScripts(true);
            RapidHardware.Transcript.AddTranscript(oRapidHardware.HardwareScripts.Transcript);
            long lCycles = oRapidHardware.SystemInterface.SystemControl.ClockCycles();
            lblClock.Text = lCycles.ToString();
            UpdateEvent();
        }

        private void cmdClock_Click(object sender, EventArgs e)
        {
            if (oRapidHardware.SystemInterface.SystemControl.IsClockRunning())
            {
                oRapidHardware.SystemInterface.SystemControl.StopClock();
            }
            else
            {
                oRapidHardware.SystemInterface.SystemControl.StartClock();
            }
            UpdateEvent();
        }

        private void cmdRefresh_Click(object sender, EventArgs e)
        {
            UpdateEvent();
        }

        public void RefreshSignalViews()
        {
            UpdateEvent();
        }

        private void cmdMicroStep_Click(object sender, EventArgs e)
        {
            //SignalView oPC = RapidHardware.SystemInterface.GetSignalView(sPCSignal);
            //SignalView oOp = RapidHardware.SystemInterface.GetSignalView(sNextOpSignal);

            if (sCodeLine.Length > 5)
            {
                string sCommand = sCodeLine.Substring(0, 4).ToUpper();
                if (sCommand == "WRITE" || sCommand == "READ_")
                    oRapidHardware.SystemInterface.SystemControl.Go(15);
            }            
            while (oOp.ValueAsString.Trim() != "1")
            {
                oRapidHardware.SystemInterface.SystemControl.Go(1);
            }
            oRapidHardware.SystemInterface.SystemControl.Go(1);
            while (oOp.ValueAsString.Trim() != "1")
            {
                oRapidHardware.SystemInterface.SystemControl.Go(1);
            }
            int iPC = oPC.ValueAsInt;
            lblMicroAddress.Text = iPC.ToString();
            if (oMicroTrace != null)
            {
                sCodeLine = oMicroTrace.SetAddress(iPC);
            }
            UpdateEvent();
        }

        private void ChipClock_Load(object sender, EventArgs e)
        {

        }

        private void cmdMicroDBG_Click(object sender, EventArgs e)
        {
            if (oMicroTrace == null)
            {
                cmdMicroDBG.Visible = false;
                return;
            }
            tmrDBG.Enabled = !tmrDBG.Enabled;
            if (!tmrDBG.Enabled)
                UpdateEvent();
        }

        private void tmrDBG_Tick(object sender, EventArgs e)
        {
            if (!tmrDBG.Enabled)
                return;
            if (sCodeLine.Length > 5)
            {
                string sCommand = sCodeLine.Substring(0, 4).ToUpper();
                if (sCommand == "WRITE" || sCommand == "READ_")
                    oRapidHardware.SystemInterface.SystemControl.Go(15);
            }
            while (oOp.ValueAsString.Trim() != "1")
            {
                oRapidHardware.SystemInterface.SystemControl.Go(1);
            }
            oRapidHardware.SystemInterface.SystemControl.Go(1);
            while (oOp.ValueAsString.Trim() != "1")
            {
                oRapidHardware.SystemInterface.SystemControl.Go(1);
            }
            int iPC = oPC.ValueAsInt;
            //lblMicroAddress.Text = iPC.ToString();
            sCodeLine = oMicroTrace.SetAddress(iPC);
            if (sCodeLine == "BREAK")
            {
                tmrDBG.Enabled = false;
                UpdateEvent();
            }
            //UpdateEvent();
        }
    }
}
